#pragma once 

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

class Sock
{
public:
  static int Socket()
  {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
      perror("create sock");
      std::cout << "errno :" << errno << std::endl;
      exit(2);
    }
    return sock;
  }

  static void Bind(int sock, uint16_t port)
  {
    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(port);
    local.sin_addr.s_addr = INADDR_ANY;

    if (bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
    {
      perror("bind");
      std::cout << "errno : " << errno << std::endl;
      exit(3);
    }
  }

  static void Listen(int sock, int back_log)
  {
    if (listen(sock, back_log) < 0)
    {
      perror("listen");
      std::cout << "errno : " << errno << std::endl;
      exit(4);
    }
  }

  static int Accept(int sock)
  {
    struct sockaddr_in peer;
    memset(&peer, 0, sizeof(peer));
    socklen_t len = sizeof(peer);

    int new_sock = accept(sock, (struct sockaddr*)&peer, &len);


    if (new_sock >= 0)
    {
      uint16_t port = ntohs(peer.sin_port);

      //1.将4字节网络序列数据转换成主机序列
      //2.将4字节IP转换成为点分十进制的字符串风格
      std::string ip = inet_ntoa(peer.sin_addr);
      
      std::cout << "get a new link : [" << ip << ":" << port << "]# " << new_sock << std::endl;

      return new_sock;
    }
    return -1;

  }

  static void Connect(int sock, std::string ip, uint16_t port)
  {
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));

    server.sin_family = AF_INET;
    server.sin_port = htons(port);

    //这个函数的作用是:
    //1.将点分十进制风格的字符串IP,转换成为4个字节的IP
    //2.将4个字节的IP地址有主机序列转换成为网络序列
    server.sin_addr.s_addr = inet_addr(ip.c_str());

    if (connect(sock, (struct sockaddr*)&server, sizeof(server)) == 0)
    {
      std::cout << "connect success!" << std::endl;
    }
    else
    {
      perror("connect");
      std::cout << "errno : " << errno << std::endl;
      exit(5);
    }
  }

};
